/*   
* Project: OSMP
* FileName: ParseHandler.java
* version: V1.0
*/
package tk.mybatis.springboot.collector;

import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;

import tk.mybatis.springboot.collector.queue.MessageData;
import tk.mybatis.springboot.collector.queue.Metrics;
import tk.mybatis.springboot.collector.queue.SendQueue;
import tk.mybatis.springboot.conf.SpringUtils;
import tk.mybatis.springboot.conf.SystemGloble;
import tk.mybatis.springboot.model.TblDevice;
import tk.mybatis.springboot.model.TblSensor;
import tk.mybatis.springboot.service.DeviceService;

/**
 * Description:采集数据处理器
 * 
 * @author: wangkaiping
 * @date: 2018年3月6日 下午3:36:13上午10:51:30
 */
public class ParseHandler extends Thread {
	private static Logger logger = Logger.getLogger(ParseHandler.class);
	private Socket socket;
	private int offset = 0;
	private String ipendpoint;
	private String ip = "";
	private String port = "";
	private String dcode = "";
	private int maxTimeOut = 3;
	
	public ParseHandler(Socket socket) {
		if (socket == null) {
			throw new NullPointerException("socket is null");
		}
		this.socket = socket;
		ipendpoint = socket.getRemoteSocketAddress().toString();
		if (!StringUtils.isEmpty(ipendpoint)) {
			String[] ips = ipendpoint.replaceAll("/", "").split(":");
			ip = ips[0];
			port = ips[1];
		}
		dcode = SystemGloble.getParam(SystemGloble.COLLECTOR_CODE);
		logger.debug("----------------新的客户端连接 IP：" + ip + " PORT: " + port + " ----------");
	}

	public void run() {
		int timeOutIndex = 0;
		byte[] buffer = new byte[2048];
		int len = 0;
		try {
			socket.setSoTimeout(10000);
		} catch (SocketException e2) {
			logger.error("socket connecte failed", e2);
		}
		while (!socket.isClosed() && socket.isConnected()) {
			// byte[] cmd = Modbus.get41Cmd(0, offset);
			byte[] cmd = Modbus.get04Cmd(0, 0, 0x30);
			try {
				socket.getOutputStream().write(cmd);
				try {
					len = socket.getInputStream().read(buffer, 0, buffer.length);
				} catch (SocketTimeoutException e) {
					if(timeOutIndex >= maxTimeOut) { //连接超时大于3次结束socket连接
						socket.close();
						break;
					}else {
						++timeOutIndex;
						logger.error("time-out for get socket data and timeOutIndex: " + timeOutIndex, e);
						continue;
					}
				}
				byte[] result = new byte[len];
				for (int i = 0; i < result.length; i++) {
					result[i] = buffer[i];
				}
				try {
					Modbus mb = new Modbus(result);
					String d=new String();
					for(byte b : result) {
						d+=String.format("%02X", b&0xFF)+" ";
					}
					logger.debug("------------- " + d + "-------------------------");
					if (mb.IsValid()) {
						int address = mb.Address();
						logger.debug("-------collector device : " + dcode + address + " 数据上报开始---------");
						String deviceId = CollectorServer.getDevice(dcode + String.valueOf(address));//从缓存获取设备地址
						if(StringUtils.isEmpty(deviceId)) {//缓存中没有从数据库查询一次
							String did = this.getDeviceId(address);
							if (!StringUtils.isEmpty(did)) {
								deviceId = did;
								CollectorServer.setDeviceMapping(dcode + String.valueOf(address), deviceId);
							}else {
								logger.debug("---------未查询到：" + dcode+address+" 关联的配置------------");
							}
						}
						
						if (!StringUtils.isEmpty(deviceId)) {
							List<TblSensor> sensors = getSensor(deviceId);
							if (null != sensors && sensors.size() > 0) {
								int code = mb.Code();
								Long timestamp = mb.getTime().getTime() / 1000;
								logger.debug("功能码:" + code + " timestamp: " +timestamp);
								logger.debug("-----------------------------------------------");
								MessageData message = MessageData.of();
								message.setDeviceId(deviceId);
								
								for (TblSensor i : sensors) {
									short va = mb.getValue(i.getIoPort());
									if (va == -23768) {
										logger.debug(i.getRemark() + " data error");
										continue;
									}
									float values = 0.00f;
									if (i.getLivalue() == 0) {
										values = va / 1.00f;
									}
									if (i.getLivalue() == 1) {
										values = va / 10.00f;
									}
									if (i.getLivalue() == 2) {
										values = va / 100.00f;
									}
									logger.debug("          "+i.getRemark() + " : " + values + "         ");
									message.put(Metrics.of(i.getRemark(), values, timestamp, ip, i.getId(),dcode+address, deviceId));
								}
								logger.debug("-----------------------------------------------");
								SendQueue.addMessageData(message);
							}else {
								logger.debug("---------------未查询到 " + dcode + address+" 的传感器-------------");
							}
							// offset++;
						}

					} else {
						String temp=new String();
						for(byte b : result) {
							temp+=String.format("%02X", b&0xFF)+" ";
						}
						logger.error("CRC校验失败:"+temp);
					}
				} catch (Exception e) {
					logger.error("modbus 解析错误", e);
				}
			} catch (IOException e) {
				logger.error("socket connect error", e);
				try {
					socket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			try {
				Thread.sleep(60000);
			} catch (InterruptedException e) {
				logger.error(e.getMessage(), e);
			}
		}
		logger.error("客户端 连接断开 ip:" + ip +" port:" + port);
	}

	private String getDeviceId(int address) {
		DeviceService deviceService = SpringUtils.getBean(DeviceService.class);
		TblDevice device = deviceService.getDevicesByAddress(address);
		if (null != device) {
			return device.getId();
		}
		return null;
	}

	private List<TblSensor> getSensor(String deviceId) {
		DeviceService deviceService = SpringUtils.getBean(DeviceService.class);
		List<TblSensor> sensors = deviceService.getSensorByDid(deviceId);
		return sensors;
	}
	
}
